Skip to content

fix(codex): route commentary-phase text to the reasoning channel (salvage #58696 + #41343) - #58868

Merged
teknium1 merged 3 commits into
mainfrom
hermes/hermes-062edd1a
Jul 5, 2026
Merged

teknium1 merged 3 commits into
mainfrom
hermes/hermes-062edd1a

Conversation

@teknium1

@teknium1 teknium1 commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Codex Responses commentary/analysis-phase message text is now routed to the reasoning channel (thinking display) instead of leaking into user-visible assistant content — in both normalized responses and live streaming.

Salvages #58696 (@devatnull, broadest coverage: adapter + output_text fallback + streaming path) and #41343 (@annguyenNous, reasoning-channel destination), cherry-picked with both authorships preserved. Fixes #24933 and #41293.

Root cause: _normalize_codex_response() appended ALL message-item text to content_parts regardless of phase, so GPT-5.x pre-tool-call planning fragments ("Vision.", "Let me inspect the repo first...") were concatenated into final answers or leaked as standalone visible messages on gateways. The streaming path had no phase awareness at all.

Design: surveyed reference implementations (Codex CLI, OpenCode, pi) — all treat commentary as mid-turn narration that is never the turn's final answer. Hermes routes it through the reasoning channel so the CLI/gateway display it like thinking text: never counted as final content, never in the output_text fallback, still visible as narration.

Changes

  • agent/codex_responses_adapter.py: commentary/analysis-phase message text → reasoning_parts (not content_parts); output_text fallback skipped for commentary-only responses; raw phase-tagged items still preserved in codex_message_items for replay/prompt-cache continuity
  • agent/codex_runtime.py: _consume_codex_event_stream() tracks the active message item's phase from response.output_item.added; commentary deltas fire on_reasoning_delta instead of on_text_delta and stay out of output_text
  • tests/run_agent/test_run_agent_codex_responses.py: 3 new tests (commentary-delta routing, final_answer passthrough, no output_text fallback) + updated assertions
  • scripts/release.py: AUTHOR_MAP entry for @devatnull

Validation

Scenario Before After
commentary + tool call "planning text" in content content empty, text in reasoning, finish=tool_calls
commentary-only + output_text leaked via fallback content empty, text in reasoning, finish=incomplete
final_answer phase visible visible (unchanged), finish=stop
phase=None (legacy) visible visible (unchanged)
streaming commentary delta on_text_delta (visible) on_reasoning_delta (thinking)

Targeted suite: 85/85 passing (tests/run_agent/test_run_agent_codex_responses.py). E2E-verified all five scenarios with real imports.

Credits

Infographic

codex-commentary-reasoning-routing

devatnull and others added 3 commits July 5, 2026 05:58
…fixes #41293)

GPT-5.x models on the Codex Responses API emit short pre-tool-call
"preamble" text as message items with phase="commentary". Previously,
_normalize_codex_response() added ALL message items to content_parts
regardless of phase, causing commentary text to leak as visible
assistant content on chat gateways.

Fix: when normalized_phase is "commentary" or "analysis", route the
message text to reasoning_parts instead of content_parts. This keeps
preamble/internal planning in the reasoning channel where it belongs.

Fixes #41293
Follow-up to the salvaged #58696 (devatnull) + #41343 (annguyenNous)
commits: instead of fully suppressing commentary/analysis-phase stream
deltas, fire on_reasoning_delta so the CLI/gateway display them like
thinking text. Matches Codex CLI semantics where commentary is never
the turn's final answer, while keeping the narration visible in the
reasoning display. Adds devatnull to AUTHOR_MAP.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/gateway Gateway runner, session dispatch, delivery platform/telegram Telegram bot adapter provider/openai OpenAI / Codex Responses API labels Jul 5, 2026
@alt-glitch

Copy link
Copy Markdown

This was generated by AI during triage.

Maintainer salvage of #58696 (@devatnull) and #41343 (@annguyenNous), with both authorships preserved; Fixes #24933 and #41293. This is the authoritative version of the Codex commentary-phase leak cluster (also related: #21568, #26898). The earlier PRs should be closed in favor of this salvage once merged.

@teknium1
teknium1 merged commit b3b1e58 into main Jul 5, 2026
31 checks passed
@teknium1
teknium1 deleted the hermes/hermes-062edd1a branch July 5, 2026 13:29
tomatau added a commit to tomatau/hermes-agent that referenced this pull request Aug 30, 2026
…ll turns

The Responses API splits a "narrate then call a tool" turn into a
commentary message item plus a function_call item. Routing all
commentary to the reasoning channel (NousResearch#58868) made that narration render
as thinking text and persist with empty content, silently dropping
user-facing reports on any surface that rebuilds history from the
database.

A turn carrying tool calls is never the final answer, so the leak
NousResearch#58868 guarded against is impossible there: promote commentary to
content on that shape only. The `analysis` phase stays on the reasoning
channel unconditionally, and commentary without tool calls (or
alongside a final_answer item) keeps its current routing. Replay is
unaffected -- history resends codex_message_items verbatim and skips
content whenever those items exist, so the text is never sent twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tomatau added a commit to tomatau/hermes-agent that referenced this pull request Sep 7, 2026
…ll turns

The Responses API splits a "narrate then call a tool" turn into a
commentary message item plus a function_call item. Routing all
commentary to the reasoning channel (NousResearch#58868) made that narration render
as thinking text and persist with empty content, silently dropping
user-facing reports on any surface that rebuilds history from the
database.

A turn carrying tool calls is never the final answer, so the leak
content on that shape only. The `analysis` phase stays on the reasoning
channel unconditionally, and commentary without tool calls (or
alongside a final_answer item) keeps its current routing. Replay is
unaffected -- history resends codex_message_items verbatim and skips
content whenever those items exist, so the text is never sent twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tomatau added a commit to tomatau/hermes-agent that referenced this pull request Sep 12, 2026
…ll turns

The Responses API splits a "narrate then call a tool" turn into a
commentary message item plus a function_call item. Routing all
commentary to the reasoning channel (NousResearch#58868) made that narration render
as thinking text and persist with empty content, silently dropping
user-facing reports on any surface that rebuilds history from the
database.

A turn carrying tool calls is never the final answer, so the leak
content on that shape only. The `analysis` phase stays on the reasoning
channel unconditionally, and commentary without tool calls (or
alongside a final_answer item) keeps its current routing. Replay is
unaffected -- history resends codex_message_items verbatim and skips
content whenever those items exist, so the text is never sent twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tomatau added a commit to tomatau/hermes-agent that referenced this pull request Sep 13, 2026
…ll turns

The Responses API splits a "narrate then call a tool" turn into a
commentary message item plus a function_call item. Routing all
commentary to the reasoning channel (NousResearch#58868) made that narration render
as thinking text and persist with empty content, silently dropping
user-facing reports on any surface that rebuilds history from the
database.

A turn carrying tool calls is never the final answer, so the leak
content on that shape only. The `analysis` phase stays on the reasoning
channel unconditionally, and commentary without tool calls (or
alongside a final_answer item) keeps its current routing. Replay is
unaffected -- history resends codex_message_items verbatim and skips
content whenever those items exist, so the text is never sent twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tomatau added a commit to tomatau/hermes-agent that referenced this pull request Sep 13, 2026
…ll turns

The Responses API splits a "narrate then call a tool" turn into a
commentary message item plus a function_call item. Routing all
commentary to the reasoning channel (NousResearch#58868) made that narration render
as thinking text and persist with empty content, silently dropping
user-facing reports on any surface that rebuilds history from the
database.

A turn carrying tool calls is never the final answer, so the leak
content on that shape only. The `analysis` phase stays on the reasoning
channel unconditionally, and commentary without tool calls (or
alongside a final_answer item) keeps its current routing. Replay is
unaffected -- history resends codex_message_items verbatim and skips
content whenever those items exist, so the text is never sent twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tomatau added a commit to tomatau/hermes-agent that referenced this pull request Sep 27, 2026
…ll turns

The Responses API splits a "narrate then call a tool" turn into a
commentary message item plus a function_call item. Routing all
commentary to the reasoning channel (NousResearch#58868) made that narration render
as thinking text and persist with empty content, silently dropping
user-facing reports on any surface that rebuilds history from the
database.

A turn carrying tool calls is never the final answer, so the leak
content on that shape only. The `analysis` phase stays on the reasoning
channel unconditionally, and commentary without tool calls (or
alongside a final_answer item) keeps its current routing. Replay is
unaffected -- history resends codex_message_items verbatim and skips
content whenever those items exist, so the text is never sent twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tomatau added a commit to tomatau/hermes-agent that referenced this pull request Sep 29, 2026
…ll turns

The Responses API splits a "narrate then call a tool" turn into a
commentary message item plus a function_call item. Routing all
commentary to the reasoning channel (NousResearch#58868) made that narration render
as thinking text and persist with empty content, silently dropping
user-facing reports on any surface that rebuilds history from the
database.

A turn carrying tool calls is never the final answer, so the leak
content on that shape only. The `analysis` phase stays on the reasoning
channel unconditionally, and commentary without tool calls (or
alongside a final_answer item) keeps its current routing. Replay is
unaffected -- history resends codex_message_items verbatim and skips
content whenever those items exist, so the text is never sent twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tomatau added a commit to tomatau/hermes-agent that referenced this pull request Sep 29, 2026
…ll turns

The Responses API splits a "narrate then call a tool" turn into a
commentary message item plus a function_call item. Routing all
commentary to the reasoning channel (NousResearch#58868) made that narration render
as thinking text and persist with empty content, silently dropping
user-facing reports on any surface that rebuilds history from the
database.

A turn carrying tool calls is never the final answer, so the leak
content on that shape only. The `analysis` phase stays on the reasoning
channel unconditionally, and commentary without tool calls (or
alongside a final_answer item) keeps its current routing. Replay is
unaffected -- history resends codex_message_items verbatim and skips
content whenever those items exist, so the text is never sent twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/telegram Telegram bot adapter provider/openai OpenAI / Codex Responses API type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Codex Responses commentary-phase tool planning leaks as visible Telegram text

4 participants